library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;


entity Control_Unit is
generic(	opSize	: integer := 4);
port(	clk			: in   std_logic;
		rst			: in   std_logic;
		opcode		: in   std_logic_vector (opSize-1 downto 0);		-- opcode form the IR
		alu_mux		: out std_logic_vector (2 downto 0);			-- operation sent to the ALU
		right_mux		: out std_logic;							-- right muxer pilot
		mem_wr		: out std_logic;							-- read or write in the datamem
		w_en		: out std_logic;							-- write enable for the register file
		is_jump		: out std_logic;							-- control the jump muxer in MM
		wb_mux 		: out std_logic;							-- writeback muxer pilot	
		en_if 		: out std_logic;
		en_id 		: out std_logic;
		en_ex 		: out std_logic;
		en_mm 		: out std_logic
);
end Control_Unit;

architecture Behavioral of Control_Unit is
signal en 	 : std_logic_vector(2 downto 0);
begin

ENBL: process (clk,rst)
begin
		
	if rst='1' then
		en 		<= "000";
		en_if 	<= '0';
		en_id 	<= '0';
		en_ex 	<= '0';
		en_mm 	<= '0';
	elsif rising_edge(clk) then
		case en is
			when "000" =>
				en_if 	<= '1';
				en_id 	<= '0';
				en_ex 	<= '0';
				en_mm 	<= '0';
				en 		<= "001";
			when "001" =>
				en_if 	<= '0';
				en_id 	<= '1';
				en_ex 	<= '0';
				en_mm 	<= '0';
				en 		<= "011";
			when "011" =>
				en_if 	<= '0';
				en_id 	<= '0';
				en_ex 	<= '1';
				en_mm 	<= '0';
				en 		<= "110";
			when "110" =>
				en_if	<= '0';
				en_id	<= '0';
				en_ex	<= '0';
				en_mm 	<= '1';
				en 		<= "100";
			when "100" =>
				en_if	<= '0';
				en_id	<= '0';
				en_ex	<= '0';
				en_mm 	<= '0';
				en 		<= "000";
			when others =>
				en_if	<= '0';
				en_id 	<= '0';
				en_ex 	<= '0';
				en_mm 	<= '0';
				en 		<= "000";
		end case;
	end if;
end process ENBL;

DECODE: process (opcode)
begin

--default cases
wb_mux		<= '1';			-- memory or alu output
w_en		<= '1';			-- enable register file
mem_wr		<= '0';			-- memory read (1 to write)

is_jump		<= '0';			-- don't jump
right_mux		<= not opcode(3);	-- 1 -> imm; 0 -> reg

case opcode(3 downto 0) is
	when "0111" =>			-- JUMP
		alu_mux 		<= "111";
		is_jump 		<= '1';		-- jump
		right_mux		<= '1';		-- immediate
		w_en 		<= '0';		-- don't write on RF
	when "1000" | "1111" =>	-- LOAD/STORE
		alu_mux 		<= "111";
		right_mux		<= '1';		-- immediate input
		wb_mux		<= '0';		-- memory output
		mem_wr		<= (opcode(3) and opcode(2) and opcode(1) and opcode(0)); 
			-- only STORE can write on RAM
		w_en		<= (opcode(3) and not opcode(2) and not opcode(1) and not opcode(0));
			-- only LOAD can write on RF
	when others =>			-- any other operation
		alu_mux 		<= opcode (2 downto 0);
end case;


end process DECODE;

end architecture;